﻿using System;
using System.ComponentModel;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using System.Collections.Generic;
using System.Xml;
using System.Text;
using System.IO;
using System.Xml.Xsl;
using System.Xml.XPath;
using SP = Microsoft.SharePoint.WebPartPages;

namespace LB.SharePoint.XSLTListViewRenderer.XSLTListViewPart
{
    [ToolboxItemAttribute(false)]
    public class XSLTListViewPart : WebPart, IWebEditable
    {
        const string _defaultXSL = "";
        private string _listGuid;
        [Personalizable]
        public string ListGuid
        {
            get { return this._listGuid; }
            set { this._listGuid = value; }
        }

        private string _viewGuid;
        [Personalizable]
        public string ViewGuid
        {
            get { return this._viewGuid; }
            set { this._viewGuid = value; }
        }
        
        [WebBrowsable]
        [Personalizable(PersonalizationScope.Shared)]
        [WebDisplayName("XSLT Definition")]
        [WebDescription("Enter the XSLT definition")]
        [SP.SPWebCategoryName("XSL")]
        public string XSLTSource { get; set; }

        protected override void CreateChildControls()
        {
            if (!String.IsNullOrEmpty(ListGuid))
            {
                //Build standard list output.
                this.Controls.Add(BuildPartOutput());
            }
            else
            {
                HyperLink hl = new HyperLink();
                hl.NavigateUrl = String.Format("javascript:ShowToolPane2Wrapper('Edit','129','{0}');", this.ID);
                hl.ID = String.Format("MsoFrameworkToolpartDefmsg_{0}", this.ID);
                hl.Text = "Click here to configure this web part";
                this.Controls.Add(hl);
            }
        }

        private Control BuildPartOutput()
        {
            Control webPartOutput = new Control();
            string xmlOutput = BuildListXml();
            if (String.IsNullOrEmpty(XSLTSource))
            {
                //Render an unordered list
                webPartOutput.Controls.Add(new LiteralControl(xmlOutput));
            }
            else
            {
                webPartOutput.Controls.Add(new LiteralControl(ApplyXSLTransformation(xmlOutput,XSLTSource)));
            }
            return webPartOutput;
        }

        EditorPartCollection IWebEditable.CreateEditorParts()
        {
            List<EditorPart> editors = new List<EditorPart>();
            XSLTEditorPart editorPart = new XSLTEditorPart();
            editorPart.ID = this.ID + "_editorPart";
            editors.Add(editorPart);
            return new EditorPartCollection(editors);
        }

        object IWebEditable.WebBrowsableObject
        {
            get 
            {
                return this;
            }
        }

        private string BuildListXml()
        {
            XmlWriterSettings xmlSettings = new XmlWriterSettings();
            xmlSettings.Encoding = new UTF8Encoding(false);
            MemoryStream memoryStream = new MemoryStream(1024);
            XmlWriter xmlWriter = XmlWriter.Create(memoryStream, xmlSettings);

            xmlWriter.WriteStartDocument();
            xmlWriter.WriteStartElement("rss");
            xmlWriter.WriteAttributeString("version", "2.0");
            xmlWriter.WriteStartElement("channel");

            using (SPWeb web = SPContext.Current.Web)
            {
                try
                {
                    SPList list = web.Lists[new Guid(this.ListGuid)];
                    SPView view = string.IsNullOrEmpty(this.ViewGuid) ?
                        list.DefaultView : list.Views[new Guid(this.ViewGuid)];

                    xmlWriter.WriteElementString("title", list.Title);
                    xmlWriter.WriteElementString("link", list.DefaultViewUrl);
                    xmlWriter.WriteElementString("description", list.Description);

                    foreach (SPListItem item in list.Items)
                    {
                        xmlWriter.WriteStartElement("item");
                        foreach (var field in view.ViewFields)
                        {
                            try
                            {
                                string value = item[field.ToString()].ToString();
                                if (value.Contains("http"))
                                {
                                    string[] urlArray = value.Split(Convert.ToChar(","));
                                    xmlWriter.WriteElementString(field.ToString(), urlArray[0]);
                                }
                                else
                                {
                                    xmlWriter.WriteElementString(field.ToString(), value);
                                }
                            }
                            catch { }
                        }
                        xmlWriter.WriteEndElement();
                    }
                }
                catch
                {
                }
            }

            xmlWriter.WriteEndElement();
            xmlWriter.WriteEndElement();
            xmlWriter.WriteEndDocument();

            xmlWriter.Flush();

            Byte[] buffer = new Byte[memoryStream.Length];
            buffer = memoryStream.ToArray();
            return Encoding.Default.GetString(buffer);
        }

        public string ApplyXSLTransformation(string xmlString, string xsltString)
        {
            string strHtml;

            xsltString = xsltString.Replace(Environment.NewLine, "");

            //Read the strings into xml
            XmlReader xmlReader = XmlReader.Create(new StringReader(xmlString));
            XmlReader xslReader = XmlReader.Create(new StringReader(xsltString));

            //  Transform the xml by using the provided xsl
            XslCompiledTransform xslTransform = new XslCompiledTransform();
            XPathDocument xmlPathDocument = new XPathDocument(xmlReader);

            xslTransform.Load(xslReader, new XsltSettings(false, true), new XmlUrlResolver());

            // Write the transformed html into a string
            MemoryStream memoryStream = new MemoryStream();
            XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.ASCII);
            StreamReader streamReader = new StreamReader(memoryStream);
            xslTransform.Transform(xmlPathDocument, xmlTextWriter);
            memoryStream.Position = 0;
            strHtml = streamReader.ReadToEnd();
            streamReader.Close();
            memoryStream.Close();

            // Return the value
            return strHtml;
        }
    }
}
